跳转至

[Syzkaller III]syzlang

image-20251210214201755

syzlang用于定义系统调用规约模板

通俗来说, 系统调用规约模板包含:

  1. 可以使用哪些系统调用
  2. 对于1中可能的每个系统调用, 他可能的参数是什么格式的
  3. 解决资源依赖问题, 比如文件描述符fd
include <linux/fs.h>
open$testxy(file ptr[in, string["/proc/test1"]], flags flags[proc_open_flags], mode flags[proc_open_mode]) fd
read$testxy(fd fd, buf buffer[out], count len[buf])
write$testxy(fd fd, buf buffer[in], count len[buf])

proc_open_flags = O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, FASYNC, O_CLOEXEC, O_CREAT, O_DIRECT, O_DIRECTORY, O_EXCL, O_LARGEFILE, O_NOATIME, O_NOCTTY, O_NOFOLLOW, O_NONBLOCK, O_PATH, O_SYNC, O_TRUNC, __O_TMPFILE
proc_open_mode = S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH

这里 open$testxy为了和其他模块的open调用规约区分开

比如对于模块A可以有 open$a

对于模块B可以有 open$b

这样可以在syz-manager的config文件中指定启用哪个系统调用, 比如

        "enable_syscalls":[
              "open$testxy",
              "read$testxy",
              "write$testxy"
        ],

有了这个模板后, 模糊测试器就可能指导产生如下syzlang源码:

r0 = open$testxy(&(0x7f0000000040), 0x28441, 0x21)
write$testxy(r0, 0x0, 0x0)

使用syz-execprog可以生成等价的一份c源码, 里面带着syz-execprog生成的注释, 方便理解

// autogenerated by syzkaller (https://github.com/google/syzkaller)

#define _GNU_SOURCE

#include <endian.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

uint64_t r[1] = {0xffffffffffffffff};

int main(void)
{
  syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul,
          /*fd=*/(intptr_t)-1, /*offset=*/0ul);
  syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul,
          /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul,
          /*fd=*/(intptr_t)-1, /*offset=*/0ul);
  syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul,
          /*fd=*/(intptr_t)-1, /*offset=*/0ul);
  const char* reason;
  (void)reason;
  intptr_t res = 0;
  if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
  }
  //  open$testxy arguments: [
  //    file: ptr[in, buffer] {
  //      buffer: {2f 70 72 6f 63 2f 74 65 73 74 31 00} (length 0xc)
  //    }
  //    flags: proc_open_flags = 0x28441 (8 bytes)
  //    mode: proc_open_mode = 0x21 (8 bytes)
  //  ]
  //  returns fd
  memcpy((void*)0x200000000040, "/proc/test1\000", 12);
  res = syscall(
      __NR_open, /*file=*/0x200000000040ul,
      /*flags=O_NOFOLLOW|O_LARGEFILE|O_CREAT|O_APPEND|O_WRONLY*/ 0x28441ul,
      /*mode=S_IXOTH|S_IRGRP*/ 0x21ul);
  if (res != -1)
    r[0] = res;
  //  write$testxy arguments: [
  //    fd: fd (resource)
  //    buf: nil
  //    count: len = 0x0 (8 bytes)
  //  ]
  syscall(__NR_write, /*fd=*/r[0], /*buf=*/0ul, /*count=*/0ul);
  return 0;
}

具体的syzlang语法见:

syzkaller/docs/syscall_descriptions.md at master · google/syzkaller · GitHub

syzkaller/docs/syscall_descriptions_syntax.md at master · google/syzkaller · GitHub